/*
 *  Copyright (c) 2010 Andy Aspell-Clark
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use,
 *  copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following
 *  conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 */
package uk.org.aspellclark.gedcom.controller;

import java.io.File;

import uk.org.aspellclark.gedcom.model.ChangeDate;
import uk.org.aspellclark.gedcom.model.IncrementedId;
import uk.org.aspellclark.gedcom.model.records.FamRecord;
import uk.org.aspellclark.gedcom.model.records.IndividualRecord;
import uk.org.aspellclark.gedcom.model.records.NoteRecord;

import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.Configuration;

/**
 * @author     andy
 * @created    29 April 2010
 */
public class Db4oController {
	/* {version=1.0.0.00, author=Andy Aspell-Clark, src_path=F:\Android\Workspace\GedcomLibrary\src, since=May 2010}*/

	private static Db4oController instance = null;

	public static Db4oController getInstance() {
		if (Db4oController.instance == null) {
			Db4oController.instance = new Db4oController();
		}
		return Db4oController.instance;
	}

	public ObjectContainer db;

	public String dbFilename = "./db.db4o";

	private Db4oController() {
	}

	public void clearDatabase() {
		ObjectSet<Object> result = this.db.queryByExample(new Object());
		while (result.hasNext()) {
			this.db.delete(result.next());
		}
		this.db.commit();
	}

	/**
	 *  commit any pending database changes and 
	 *  close the connection to the database.
	 */
	public void closeDatabase() {
		//Log.w("DbController", "closing database");
		if (this.db != null) {
			this.db.commit();
			this.db.close();
		}
		this.db = null;
	}

	private Configuration dbConfig() {
		Configuration config = Db4o.newConfiguration();

		//config.cascadeOnUpdate(true);
		config.updateDepth(5);

		String xrefFieldName = "xref";

		config.objectClass(IndividualRecord.class).objectField(xrefFieldName).indexed(true);
		config.objectClass(FamRecord.class).objectField(xrefFieldName).indexed(true);
		config.objectClass(NoteRecord.class).objectField(xrefFieldName).indexed(true);
		config.objectClass(ChangeDate.class).objectField(xrefFieldName).indexed(true);

		config.objectClass(IndividualRecord.class).cascadeOnUpdate(true);
		//config.objectClass(IndividualRecord.class).updateDepth(5);

		config.objectClass(FamRecord.class).cascadeOnUpdate(true);
		//config.objectClass(FamRecord.class).updateDepth(5);

		config.objectClass(NoteRecord.class).cascadeOnUpdate(true);
		//config.objectClass(NoteRecord.class).updateDepth(5);

		config.objectClass(ChangeDate.class).cascadeOnUpdate(true);
		//config.objectClass(ChangeDateRecord.class).updateDepth(5);

		config.testConstructors(true);
		config.optimizeNativeQueries(true);
		config.weakReferences(false);

		return config;
	}

	public void deleteDatabase() {
		this.closeDatabase();
		File dbFile = new File(this.dbFilename);
		dbFile.delete();
	}

	@Override
	protected void finalize() throws Throwable {
		try {
			this.closeDatabase();
		} finally {
			super.finalize();
		}
	}

	public long getNextId() {
		ObjectSet<IncrementedId> result = this.db.queryByExample(IncrementedId.class);
		IncrementedId ii = null;
		long nextId;
		if (result.hasNext()) {
			ii = result.next();
		} else {
			ii = new IncrementedId();
		}
		nextId = ii.getNextId();
		this.db.store(ii);
		return nextId;
	}

	/**
	 *  open a connection to the database.
	 */
	public ObjectContainer openDatabase() {
		//Log.w("DbController", "opening database");
		try {
			if (this.db == null || this.db.ext().isClosed()) {
				this.db = Db4o.openFile(this.dbConfig(), this.dbFilename);
			}
			return this.db;
		} catch (Exception e) {
			//Log.e(DBHelper.class.getName(), e.toString());
			return null;
		}
	}

}
